/*
 * @Author: lcs
 * @Date: 2021-06-07 10:56:48
 * @LastEditTime: 2021-06-07 14:46:04
 * @LastEditors: lcs
 * @FilePath: \vue2-ts-base\src\text-ts.ts
 * @Description: 
 */

// 类型注解 原始类型：number string object sysbol null undefined boolean
// 类型注解
let val1 = '1231'
val1 = 'abc'


// 类型推论
const val2 = true;


// 联合类型
let val3: string | undefined;
val3 = undefined
val3 = '123'


// 类型数组
let arr: string[];
arr = ['tom']
arr = ['12']


// 任意类型
let varAny: any;
varAny = '1231'
varAny = true


// any 用于数组
let arrAny: any[]
arrAny = ['1231']
arrAny = [123, true]


// 函数类型约束
function greet(person: string): string {
  return '您好 ' + person
}
const msg = greet('tom')


// void类型
function warn(): void {
  console.log('hah')
}

// 对象object  不是原始类型就是对象类型
function fun1(o: object) { }
// 正确调用
fun1({ a: '12' })
// fun1(1)报错


// 调用fun2  参数必须为对象 且有porp 参数 值为number 类型 
function fun2(o: { prop: number }): number {
  o.prop = 100
  return o.prop
}
fun2({ prop: 12 })


// 类型别名type; type声明的是一种类型结构 用在：后面用来约束类型
type Prop = { prop: number }
function fun3(o: Prop) { }  // 等同于fun2
// type 和interface的区别 。基本完全相同


// 类型断言
const someValue: any = '123123'
// 让编译器 把someValue 当成字符串去对待 通过as 断言类型
const strLen = (someValue as string).length

// 交叉类型
type First = { first: number }
type Second = { second: boolean }
// 扩展新的类型
type FirstAndSecond = First & Second
function fun4(): FirstAndSecond {
  return { first: 1, second: true }
}


// 函数
// 1.设置的就是必传参数
// 2. 设置默认值 msg='abc'
function greeting(person: string, msg1 = 'abc', msg2?: string): string {
  return '您好 ' + person
}
greeting('tom')


// 函数重载：场景主要源码和框架 函数用参数个数 类型或者返回值类型区分同名函数
// 先声明 再实现
//1.声明
function watch(cb1: () => void): void;
function watch(cb1: () => void, cb2:(v1: any, v2: any) => void): void;

// 实现
function watch(cb1: () => void, cb2?:(v1: any, v2: any) => void) {
  if (cb1 && cb2) {
    console.log("执行重载2");

  } else {
    console.log("执行重载1");

  }
}
watch(()=>{},()=>{})

// class 类
class Parent {
  private _foo = 'foo'  // 私有属性 不能在类的外部访问
  protected bar = 'bar'  // 保护属性 只能在子类中访问

  // 参数属性：构造函数加修饰符，能够定义为成员属性
  constructor(public tua ='tua') {}
 
  // 方法也有修饰符 私有方法
  private someMethods() {}

  // 存取器，属性方式访问，可添加额外逻辑。控制读写性
  get foo(){
    return this._foo
  }
  set foo(val){
    this._foo =val
  }
}
const p = new Parent()
p.tua //通过p. 只能访问到foo tua 属性

class Child extends Parent{
  say(){
    // this.bar
    // 父类中的 bar 可再这里访问到
  }
}
const a  = new Child()

a.say() //通过p. 只能访问到父类中 foo tua属性和自身的say方法 注意父类中的 (bar) protected 这里也访问不到